package com.wjerp.tplus.server.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * RedisUtils 工具类.
 * @author lishuailei
 */
@Component
public class RedisUtils {
    public static Logger logger = LoggerFactory.getLogger(RedisUtils.class);


    @Resource
    private RedisTemplate<String,Object> redisTemplate;


    private static final String LOCK_SUCCESS = "OK";
    private static final Long RELEASE_SUCCESS = 1L;
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final String UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    private static final int RETRY_TIME = 9999;

    /**
     * 批量删除对应的value.
     *
     * @param keys the keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除对应的value.
     * @param mapName
     * @param keys the keys
     */
    public Boolean removeMap(String mapName,String... keys) {
        boolean result = false;
        try {
            HashOperations<String, Object, Object> operations = redisTemplate.opsForHash();
            operations.delete(mapName,keys);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 批量删除key.
     *
     * @param pattern the pattern
     */
    public void removePattern(final String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0) {
            redisTemplate.delete(keys);
        }
    }

    /**
     * 删除对应的value.
     *
     * @param key the key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判断缓存中是否有对应的value.
     *
     * @param key the key
     * @return true, if successful
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }
    
    /**
     * Keys.
     *
     * @param keyPattern the key pattern
     * @return the sets the
     */
    public Set<String> keys(final String keyPattern){
    	return redisTemplate.keys(keyPattern);
    	
    }

    /**
     * 读取缓存.
     *
     * @param key the key
     * @return the object
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    /**
     * 写入缓存.
     *
     * @param key the key
     * @param value the value
     * @return true, if successful
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 写入缓存.
     *
     * @param key the key
     * @param value the value
     * @param expireTime the expire time
     * @return true, if successful
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * Sets the map.
     *
     * @param mapName the map name
     * @param key the key
     * @param value the value
     * @return true, if successful
     */
    public boolean setMap(final String mapName, final String key, String value) {
        boolean result = false;
        try {
            HashOperations<String, Object, Object> operations = redisTemplate.opsForHash();
            operations.put(mapName,key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * gets the map.
     *
     * @param mapName the map name
     * @return true, if successful
     */
    public Map<Object, Object> getMap(final String mapName) {
        Map<Object, Object> resultMap = new HashMap<>();
        try {
            HashOperations<String, Object, Object>  operations = redisTemplate.opsForHash();
            resultMap = operations.entries(mapName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    /**
     * get the map.
     * @param mapName the map name
     * @param key the key
     * @return true, if successful
     */
    public Object getMap(final String mapName, final String key) {
        Object result = null;
        try {
            HashOperations<String, Object, Object>  operations = redisTemplate.opsForHash();
            result = operations.get(mapName,key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    public void delete(final String mapName, final String key) {
        HashOperations<String, Object, Object>  operations = redisTemplate.opsForHash();
        operations.delete(mapName,key);
    }

    /**
     * 加锁
     * @param lockKey
     * @param expireTime 强制锁释放时间
     * @return
     */
    public boolean tryLock(String lockKey, String requestId,int expireTime) {
        Long start = System.currentTimeMillis();
        try{
            for(;;){
                //SET命令返回OK ，则证明获取锁成功
                Boolean ret = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS);
                if(ret){
                    return true;
                }
                //否则循环等待，在timeout时间内仍未获取到锁，则获取失败
                long end = System.currentTimeMillis() - start;
                if (end>=RETRY_TIME) {
                    return false;
                }
            }
        }finally {

        }
    }

    /**
     * 释放分布式锁
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public boolean unlock(String lockKey, String requestId) {
        return redisTemplate.delete(lockKey);
//        RedisScript<String> redisScript = new DefaultRedisScript<>(UNLOCK_SCRIPT, String.class);
//        Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey),requestId);
//        if(LOCK_SUCCESS.equals(result)) {
//            return true;
//        }
    }


    /**
     * 自增键(当天有效)
     * @param key 标示键
     * @return 自增后值
     */
    public Long incrementByDay(String key){
        redisTemplate.expire(key, 24, TimeUnit.HOURS);
        Long value = redisTemplate.opsForValue().increment(key);
        return value;
    }
}
